#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "athread.h"
#include "sys/time.h"

#define FREQ 1500000000
#define alpha_d 0.0876
#define beta_d 0.0765
#define my_ceil(a,b) \
     (a%b==0)?a/b:a/b+1


double A[2][SIZEX][SIZEY];
double test[2][SIZEX][SIZEY];
int thread_num, ntilex, ntiley, ntilez;
int ITER,iter,N; ////n is the num of tiles that each thread assigned
int starti[64];
int startj[64];

#ifdef PROFILING
unsigned long slave_comp_count[64]={0};
unsigned long slave_dma_count[64]={0};
unsigned long total_dma_count=0;
unsigned long total_comp_count=0;
#endif

extern SLAVE_FUN(func)();
unsigned long rpcc()
{
  unsigned long time;
  asm("rtc %0":"=r"(time):);
  return time;
}
init()
{
  int i,j;
  for(i = 0; i < SIZEX; i++)
     for(j = 0; j < SIZEY; j++)
     {
       A[1][i][j] = (double)(i*2.5 + j*3.3) /3.0;
       A[0][i][j]=A[1][i][j];
     }
}
int check(const int iter)
{
   int i,j,k;
   int itr;
   int ii,jj,kk;
   printf("begin check\n");
    for(i = 0; i < SIZEX; i++)
     for( j = 0; j < SIZEY; j++)
     {
         test[1][i][j] = (double)(i*2.5 + j*3.3) /3.0; 
         test[0][i][j]=test[1][i][j];
     }
       
    for(itr = 0; itr < iter; ++itr)
     for(i = 1; i < SIZEX - 1; i++)
      for( j = 1; j < SIZEY - 1; j++)
      {
//          if(i==1&&j==1)
  //         printf("master:%f,%f,%f,%f,%f\n",test[(itr+1)%2][i][j],test[(itr+1)%2][i-1][j],test[(itr+1)%2][i+1][j],test[(itr+1)%2][i][j-1],test[(itr+1)%2][i][j+1]);
          test[itr%2][i][j] = alpha_d * test[(itr+1)%2][i][j]+\
                         beta_d * (test[(itr+1)%2][i-1][j] + test[(itr+1)%2][i+1][j] +\
                         test[(itr+1)%2][i][j-1] + test[(itr+1)%2][i][j+1]);
      }
    for(ii = 1; ii < SIZEX - 1; ii++)
      for(jj = 1; jj < SIZEY - 1; jj++)
          if( fabs(test[(iter+1)%2][ii][jj] - A[(iter+1)%2][ii][jj]) > 1e-13){
             printf("i: %d   j:  %d \n",ii,jj);    
             printf("test: %20.20f",test[(iter+1)%2][ii][jj]);
             printf("\nA: %20.20f",A[(iter+1)%2][ii][jj]);
             printf("\nno");               
             return -1;
         }
  printf("correct\n");
  return 0;
}



int main(int argc, char** argv)
{
    int dest,src;
    int i,j,k,t;
    struct timeval start;
    struct timeval end;
    double total_time;
    unsigned long st,et;
    
    thread_num=1;
    ITER = 100;
    if(argc>1)
        thread_num = atoi(argv[1]);
    if(argc>2)
        ITER=atoi(argv[2]);
    init();
    athread_init();
    ntiley=my_ceil((SIZEY-2),BLKY);
    ntilex=my_ceil((SIZEX-2),BLKX);
    
    st=rpcc();
    athread_spawn(func,0);
    athread_join();
    et=rpcc();
    athread_halt();

#ifdef PROFILING
    for(t=0;t<thread_num;++t)
    {
      total_dma_count+=slave_dma_count[t];
      total_comp_count+=slave_comp_count[t];
    //  printf("%ld\n",slave_dma_count[t]);
    }
    //printf("total_count=%ld\ntotal_dma_count=%ld\ntotal_comp_count=%ld\n",et-st,total_dma_count,total_comp_count);
    printf("total_time=%5.3f\naver_dma_time=%5.3f\naver_comp_count=%5.3f\n",
         (float)(et-st)/FREQ,
         (float)total_dma_count/FREQ/thread_num,
         (float)total_comp_count/FREQ/thread_num);

#endif
    //printf("total_count=%ld\n",et-st);

#ifdef CHECK
    if(check(ITER))
    {
        printf(" error\n");
        exit(1);
    }
#endif
    return 0;
}

